home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Floppyshop 2
/
Floppyshop - 2.zip
/
Floppyshop - 2.iso
/
diskmags
/
0022-3.564
/
dmg-0121
/
news.txt
/
gfaexprt.asc
< prev
next >
Wrap
Text File
|
1997-04-16
|
28KB
|
707 lines
GFA PROGRAMING HINTS & TIPS
===========================
These hints and tips were taken, more or less at random, from a brilliant
disc by Han Kempen. It's called the GFA Expert disc and contains a massive
1st word file which prints out into a 120+ page, 2nd manual for GFA
version 3 users. It contains everything the GFA manual left out and more.
To back up the examples in the manual are lots of routines that can be
merged with your own programs.
The author has placed these files into the public domain and given
permission for extracts to be used in articles etc. While it is OK to pass
copies of the disc on to friends, public domain libraries must get his
written permission to distribute the disc. As far as I know, Caledonia is
the only PD library with the necessary permission to distribute this disc.
~~~OOOO~~~
There are several ways to (re)start your computer. The obvious one is to
switch the ST off, wait a few seconds (15 seconds with a 1040 ST!), and
switch on again. This is called a "cold" or "hard" reset. Your computer
suffers a little, and it takes some time. If you use the reset-button on
your ST, you perform a "warm" or "soft" reset. The operating system
automatically performs a warm reset if you switch between Low and Medium
resolution on the desktop. If you suspect a program of changing system
variables, you should always use a cold reset. After a warm reset the
system variables in low memory are not initialised again. Garbage will
stay there and will undoubtedly lead to interesting effects. You can
perform both a warm and a cold reset from GFA-Basic with the following
Procedures :
PROCEDURE coldstart
SLPOKE &H420,0
SLPOKE &H426,0 ! probably not necessary
SLPOKE &H43A,0
~XBIOS(38,L:LPEEK(4))
RETURN
'
PROCEDURE warmstart
~XBIOS(38,L:LPEEK(4))
RETURN
If you would like to boot from your second (external) drive B, try :
SLPOKE &H446,1 ! boot from drive B after next reset
@warmstart
~~~OOOO~~~
With GEMDOS-function 48 (Sversion) you can find the version of your
GEMDOS. For both the old TOS and the Blitter-TOS &H1300 (version 0.19) is
returned. The French Turbo-DOS has version 0.20 and the new Rainbow TOS of
1988 has version 0.21.
Another way to find out the version of TOS uses the system header of TOS
(not necessarily located in ROM!) :
adr%=LPEEK(&H4F2)
version$=HEX$(DPEEK(adr%+2))
The good old ROM-TOS (1986, actually not so good) has version &H0100
(1.0), the Mega-ST Blitter-TOS (1987) version &H0102 (1.2). And of course
the new TOS ('Rainbow TOS') has version 1.4. You could also examine the
date of your TOS-version :
date$=HEX$(LPEEK(adr%+24))
My ancient TOS 1.0 has '11201985' as the date.
~~~OOOO~~~
Syntax
The parser checks for correct syntax after you press <Return>. Many typo-
bugs are prevented this way. The only disadvantage is that the parser
recognizes some variables as commands. It's impossible to use the follo-
wing names as the first word on a line: data_byte|, dirty$, double,
printer$, file%, quit!. The last one is nasty, because the parser changes
the line 'quit!=FALSE' into 'QUIT!=FALSE' without warning for a syntax-
error. If you now run the program you will return to the desktop when QUIT
is encountered. Of course you have not lost your valuable program, because
you always Save before you Run. Do you really? If the parser refuses the
name of a variable, you can use LET (e.g. 'LET quit!=FALSE'). But you will
have to change the name if it is a label (e.g. the label 'data1:' could be
changed into '1data:' or 'd.ata1:').
~~~OOOO~~~
Folded Procedures
If you press <Control> <Help> on a Procedure-line, all Procedures follo-
wing and including the current one are folded/unfolded. You can unfold all
Procedures at once by putting the cursor on the first Procedure-line and
pressing <Control> <Help>. I suggest you leave all Procedures in the
Procedure-Library GFAXPERT.LIB folded, unless you want to examine a
Procedure. The editor-commands 'Find' and 'Replace' will skip folded
Procedures. Never change the Procedure-line of a folded Procedure, always
unfold it first.
~~~OOOO~~~
Tab
If you press <Tab>, the cursor jumps to the next tab-position, without
altering the current line. If you use <Left Shift> <Tab>, the line is
filled with spaces from the current cursor-position to the next tab-
position. Pressing <Right Shift> <Tab> erases all consecutive spaces to
the left of the current cursor-postition. If the current cursor-position
happens to be a space, this space and all spaces to the right are erased
as well.
~~~OOOO~~~
Cut and Paste
If you press <Control> <P>, the current line from the cursor to the end of
the line is cut, and saved in an internal buffer. <Control> <O> inserts
the saved line at the current cursor-position. You can use this method to
"cut and paste" a part of a line. Press <Control> <P>, then <Control> <O>
to restore the original line. Move the cursor to the desired position and
press <Control> <O>. Block-operations are only possible with complete
lines.
~~~OOOO~~~
Llist
There has been some confusion about the following point-commands for the
printer :
.p- - point-commands are not printed
.p+ - point-commands are printed again
.llxx - line-width
.plxx - page-length
.pa - form feed
Sometimes the commands '.cp' and '.nu' are mentioned, but I don't know how
to use these.
You can only use one point-command in one line. I use the following lines
for my printer (96 characters/line in Elite-mode) :
.p-
.n4
.lr3
.ll88
Save this as LLIST.LST and Merge it after the last line of a program
before choosing 'Llist'. The actual listing is then printed with 80
characters/line, preceded by the line-numbers (4 characters + space). If
your program is longer than 10000 lines, you should use '.n5', but in that
case you probably don't have time to read this. A nice touch is the
automatic execution of a form feed after printing the listing.
If the listing contains special characters (ASCII-code < 32 or > 126),
some of those characters might be interpreted as printer-commands. My
printer switches to condensed printing after receiving the Atari-symbol.
Installing the proper printer-driver (e.g. PTEPSON.PRG) will prevent that.
But I never install a printer-driver because there are some serious
disadvantages. Read more about it in the paragraph 'HARDCOPY'.
You can stop the printing process by pressing the 'Break'-combination
<Control> <Left Shift> <Alternate>, unless Break has been disabled with
'ON BREAK CONT'. Your printer will continue printing though, until its
input-buffer is empty, or until you turn the printer off.
~~~OOOO~~~
DUMP
Examine all variables in your program by typing 'DUMP' in Direct Mode.
Press <CapsLock> to slow down the scrolling-speed, or press the right
<Shift>-key to temporarily stop the scrolling. The Procedure Debug enables
you to use DUMP during debugging. This is the best way to discover those
nasty typo-bugs in a variable-name. You'll probably be surprised to see
the names of deleted variables as well. Also, any variable-name you used
in Direct Mode appears. All these names are SAVEd with the program! Delete
all unwanted names as follows (a RAM-disk would be convenient) :
- Load the file
- Save,A (press <Return> in Fileselector)
- New
- Merge (press <Return> again)
- Save (press <Return> once more)
The file could be much shorter after this operation.
~~~OOOO~~~
INKEY$
All keypresses are saved in the keyboard-buffer. If you don't want INKEY$
to read an "old" key, you should first clear the buffer :
REPEAT
UNTIL INKEY$="" ! clear keyboard-buffer
key$=""
REPEAT
key$=INKEY$ ! wait for new key
UNTIL key$<>""
In the following table you'll find a few useful decimal ASCII-codes you
can use after 'key$=INKEY$'. In the third column the hexadecimal scan-code
of the key is also mentioned (see paragraph 'KEYGET').
key ASC(key$) scancode
<Backspace> 8 &H0E
<Tab> 9 &H0F
<Return> and <Enter> 13 &H1C and &H72
<Esc> 27 &H01
<Delete> 127 &H53
key ASC(RIGHT$(key$))
<F1> 59 &H3B
<F10> 68 &H44
<Shift> <F1> 84 &H54
<Shift> <F10> 93 &H5D
<Help> 98 &H62
<Undo> 97 &H61
<Insert> 82 &H52
<ClrHome> 71 &H47
<Left arrow> 75 &H4B
<Right arrow> 77 &H4D
<Up arrow> 72 &H48
<Down arrow> 80 &H50
Keys in the second part of this table return a 2-byte value after INKEY$.
You only need the low byte, the high byte is &H00. That's why a Standard
Global like help$ is defined as 'CHR$(0)+CHR$(98)'. Then it's easy to
check if <Help> was pressed :
IF key$=help$
(...) ! <Help>
ENDIF
Otherwise, you have to test as follows :
IF ASC(RIGHT$(key$))=98
(...) ! <Help>
ENDIF
~~~OOOO~~~
Setscreen (XBIOS 5)
With XBIOS 5 (Setscreen) it is possible to change the resolution from Low
to Medium and from Medium to Low. Unfortunately, GEM ignores the switch,
so GEM-commands (e.g. ALERT, TEXT, MOUSE) do not work properly! But you
could change from Low to Medium resolution to show text on the TOS-screen
with PRINT (and VT52-commands). Most users will be grateful for the
improved readability of the text :
~XBIOS(5,L:-1,L:-1,1) ! switch from Low to Medium
(...) ! print text in Medium resolution
~XBIOS(5,L:-1,L:-1,0) ! and go back to Low
If you change the resolution, the VT52-emulator is automatically
initialised. You'll probably have to adjust the palette before you can
read the text without sun-glasses. Don't forget to save and restore the
old palette.
~~~OOOO~~~
Floppy Write Test
You are advised to switch the Write Verify test off :
SPOKE &H444,0 ! test off
SPOKE &H444,1 ! test on (default)
According to experts like Dave Small and Bill Wilkinson the Verify test is
a complete waste of valuable time if you write to a disk.
~~~OOOO~~~
Step Rate
You will find the current step-rate of your drive with :
PRINT DPEEK(&H440)
The following values are possible :
0 - 6 ms
1 - 12 ms
2 - 2 ms
3 - 3 ms (default)
The operating system only looks at this value after a reset (?). For an
external 5.25"-drive you probably have to use 12 ms.
~~~OOOO~~~
Bootsector
In the following table you'll find the lay-out of a bootsector. All words
are in Intel-format, except CHKSUM.
offset length name
0 2 &H6038 = branch to bootroutine
2 6 FILLER fill-bytes
8 3 SERIAL serial-number of disk
11 2 BPS bytes/sector (512)
13 1 SPC sectors/cluster (2)
14 2 RES reserved sectors (1, Bootsector)
16 1 NFATS number of FAT's (2)
17 2 NDIRS max. entries in main directory
19 2 NSECTS total sectors
21 1 MEDIA media-byte (not used by TOS)
22 2 SPF sectors/FAT (5)
24 2 SPT sectors/track
26 2 NSIDES sides (1 or 2; no joke this time)
28 2 NHID hidden sectors (ignored by TOS)
30 2 EXECFLAG start of bootcode : flag
32 2 LDMODE 0=load FNAME; <>0=load sectors
34 2 SSECT first sector (LDMODE<>0)
36 2 SECTCNT number of sectors
38 4 LDADDR load at this RAM-address
42 4 FATBUF address of FAT-buffer
46 11 FNAME filename (nnnnnnnneee) (LDMODE=0)
57 1 DUMMY fill-byte
58 boot-routine (could be a boot-virus)
510 2 CHKSUM
TOS determines if the bootsector is executable by adding all bytes. If
this sum (AND &HFFFF) equals &H1234, the bootsector is executable. If you
use GFA-Basic this probably means you have an ancient ST with TOS in RAM,
or a boot-virus. A normal GFA-disk has only &H00- or &HE5-bytes from the
offset 58.
~~~OOOO~~~
SOUND and WAVE
After a SOUND-command, the sound sometimes continues in spite of the
elapsed time. If the command is followed by another SOUND- or a WAVE-
command, the time is handled correctly. This certainly sounds like a GFA-
bug.
The easiest way to stop all sound is :
WAVE 0,0 ! turn all sound off
Sound of a certain frequency can be produced with :
SOUND ch,vol,#ROUND(125000/freq%),pause
Although our ST is not famous for its brilliant sound, you can produce
nice sound-effects with the simple commands SOUND and WAVE. Check out the
Procedures Siren.sound, Tideli.sound, Bounce1.sound and Bounce2.sound to
hear what I mean.
Dosound (XBIOS 32)
XBIOS 32 (Dosound) can be used to play music in a special format. I
propose to use the extension 'X32' for song-files in this format. The
operating system takes care of playing the music during interrupts (every
1/50th second). Take a look at the Procedures Play.song and Stop.song to
see how you could use XBIOS 32 in your programs. You can even play a song
continuously with the Procedure Play.cont.song. Temporarily stopping a
song is possible with the Procedure Interrupt.song.
If you use XBIOS 32 to play music, you are advised to switch the key-click
off. Otherwise the music will stop as soon as the user presses a key.
Once I discovered XBIOS 32 did not work during the initialization (mainly
the filling of arrays) of a large program. I had converted the program
from GFA-Basic 2.0 to 3.0, but I did not have the patience to find out
what caused this problem.
XBIOS 32 can also be used for sound-effects. I have developed the
Procedure Initio.sound for building sound-strings from a few DATA-lines.
I hereby declare this as the standard method for creating sound-strings.
After @do.sound(sound$) you can hear the sound-effect. In the following
example the sound-string bounce3$ is created :
PROCEDURE initio.sound
' *** commands in DATA-lines :
' *** REG = 14 parameters for registers 0-13
' *** END = end of sound-string
' *** PAUSE = pause (followed by time in 1/50 seconds)
' *** VAR = decrease/increase tone : channel,start,+/-step,
' *** end-value
'
bounce3.sound:
DATA REG,0,0,0,0,0,0,27,248,16,16,16,35,95,0
DATA VAR,3,255,-1,116
DATA PAUSE,255,END
RESTORE bounce3.sound
@sound.string(bounce3$)
RETURN
'
PROCEDURE sound.string(VAR s$)
LOCAL n,snd$,snd,channel,begin,step,end
s$=""
DO
READ snd$
snd$=UPPER$(snd$)
EXIT IF snd$="END"
IF snd$="REG"
FOR n=0 TO 13
READ snd
s$=s$+CHR$(n)+CHR$(snd)
NEXT n
ENDIF
IF snd$="PAUSE"
READ snd
s$=s$+CHR$(130)+CHR$(snd)
ENDIF
IF snd$="VAR"
READ channel,begin,step,end
s$=s$+CHR$(128)+CHR$(begin)+CHR$(129)+CHR$(channel)+CHR$(step)
s$=s$+CHR$(end)
ENDIF
LOOP
s$=s$+CHR$(255)+CHR$(0) ! terminator
RETURN
'
PROCEDURE do.sound(sound$)
VOID XBIOS(32,L:VARPTR(sound$))
RETURN
~~~OOOO~~~
13. MODEM
INPAUX$
With the command INPAUX$ the internal RS232-buffer is read and at the same
time cleared. You can find the address of the input-buffer with :
adr.in%=LPEEK(XBIOS(14,0))
The output-buffer can be located with :
adr.out%=LPEEK(XBIOS(14,0)+14)
INP
If you use INP(1) to read incoming bytes, you should always check with
INP?(1) if the RS232-buffer contains data.
Rsconf (XBIOS 15)
With XBIOS 15 (Rsconf) you can change the RS232-parameters. A few
baudrates :
0 - 19200 baud
1 - 9600 baud
4 - 2400 baud
7 - 1200 baud
9 - 300 baud
14 - 75 baud
Use -1 for parameters you don't want to change. Due to a TOS-bug, you
can't use 75 baud, because '14' results in 120 baud. Also, the old TOS
(pre-Blitter age) can't handle hardware handshake with RTS/CTS-signals.
Atari has released a bug-fix that should enable any TOS to use RTS/CTS.
Software handshaking (XON/XOFF) functions properly. The default
after power-up is no handshake protocol.
~~~OOOO~~~
Calculations
Try to remove all unnecessary calculations from loops, e.g. :
FOR i=1 TO 1000
x(i)=2*q*i
NEXT i
It's a better idea to calculate 2*q outside the loop :
q2=q*2
FOR i=1 TO 1000
x(i)=q2*i
NEXT i
Always try to convert floating point variables to integers before entering
a loop. Then you will be able to use the fast integer-operators. An
obvious example would be a calculation with dollars (24.37) that could be
replaced by a calculation with cents (2437). Use this method if you know
the lowest possible value of the floating point variable (0.01 in this
case) and then divide by this value. But watch out for rounding errors and
integer-overflow.
Powers of 2 can be calculated fast by setting a bit :
x%=BSET(0,6) ! faster than x%=2^6
And for the ultimate speed-freaks, multiplying with a power of 2 is
slightly faster with SHL :
y%=SHL(x%,3) ! faster than y%=MUL(x%,8)
Of course there is no overflow-control if you use SHL (or MUL).
Sometimes, calculations in a loop can be replaced by a look-up table :
FOR i=1 TO 1000
y%(i)=x|(i)^2
NEXT i
First, create a table of squares :
DIM square%(255)
FOR i=0 TO 255
square%(i)=i*i
NEXT i
Then use this table in the loop :
FOR i=1 TO 1000
y%(i)=square%(x|(i))
NEXT i
FOR ... NEXT
I use local variables in Procedures if possible. But if you intend to
compile the program later, you should declare the counter in a FOR ...
NEXT loop as a global variable. In the compiled program, the loop will be
executed faster!
If you use floating point count-variables in a FOR ... NEXT loop (or any
other loop), you could encounter unexpected problems :
FOR i#=0.1 TO 0.9 STEP 0.1
PRINT i#
NEXT i#
You would expect 0.9 as the result of the last addition (0.8 + 0.1), but
0.9 is never printed! This is not a bug in GFA-Basic, but caused by the
internal (binary) representation of floating point numbers. The last
addition results in a number slightly larger than 0.9 and therefore the
loop is left after printing 0.8 . If you insert the line
i#=ROUND(i#,14)
in the loop, you can solve this problem. But the best solution is to avoid
floating point count-variables in loops. Integer count-variables are much
faster. You could easily change the loop to :
FOR i=1 TO 9
PRINT USING "#.#";i/10
NEXT i
One more time: 'i' is a word-variable, because I use word-variables as
the default for number-variables without postfix.
If you use a floating point variable in a REPEAT UNTIL loop, you can avoid
the rounding error by using the special operator '==' :
i#=0
REPEAT
i#=i#+0.1
PRINT i#
UNTIL i#==0.9
But you can't use the '=='-operator in a FOR ... NEXT loop.
In the following two examples a byte-variable is used as the counter :
FOR i|=5 DOWNTO -1
PRINT i|
NEXT i|
'
FOR i|=250 TO 256
PRINT i|
NEXT i|
Of course, a byte-variable cannot have a value of -1 or 256. GFA does not
abort with an error-message, but skips the loops. Not a true bug perhaps,
but close.
Loops
Although you can use many different loops in GFA-Basic 3.0, there are
basically only two varieties. You can first test a condition, and then
either continue or leave the loop. Or you can first enter the loop, and
then test a condition to decide if you are going to continue or leave.
In an interpreted program the first choice is the fast FOR ... NEXT loop,
then the (slower) REPEAT ... UNTIL loop and finally the (slowest) WHILE
... WEND loop. In a compiled program all loops are executed equally fast!
If you use a DO ... LOOP, an EXIT IF condition will always take some extra
time.
Try to avoid a negative test in a loop, as this will take more time. E.g.
replace :
WHILE NOT condition!
(...)
WEND
by the much faster :
DO UNTIL condition!
(...)
LOOP
Or similarly replace :
REPEAT
(...)
UNTIL NOT condition!
by the faster :
DO
(...)
LOOP WHILE condition!
Finally, you could combine the test of one condition at the start of the
loop with the test of another condition at the end of the loop :
DO UNTIL condition_1!
(...)
LOOP WHILE condition_2!
~~~OOOO~~~
CURVE
With the command CURVE you can draw a Bezier-curve :
CURVE x1,y1,x2,y2,x3,y3,x4,y4
The Bezier-curve starts at (x1,y1) and ends at (x4,y4). The other two
points act like little magnets. You can also use this command to draw a
'normal' curve between two points by letting the points (x3,y3) and
(x4,y4) coincide. Try the following to see what I mean :
GRAPHMODE 3
MOUSE x2,y2,k
DO
CURVE 10,100,x2,y2,110,100,110,100 ! draw curve
REPEAT
MOUSE x,y,k
UNTIL x<>x2 OR y<>y2
CURVE 10,100,x2,y2,110,100,110,100 ! erase curve
x2=x
y2=y
LOOP
This method could be used to draw large letters.
~~~OOOO~~~
Line-A
The Line-A commands are faster than the corresponding VDI-commands in GFA-
Basic. The difference should be even greater after loading GDOS (?). In
the following table you can find how many times faster the Line-A command
is :
PSET / PLOT = 3
PTST / POINT = 2
HLINE / LINE = 2
ARECT / PBOX = 1.5
The syntax of Line-A commands is more complicated, but that's no problem
for us GFA-experts. Line-A commands use the 'SETCOLOR-index', so you'll
probably need the Standard Array color.index().
HLINE
An additional advantage of the commands HLINE, ARECT and APOLY is that you
don't have to change the DEFFILL-parameters in the main program. For solid
horizontal lines, use :
pattern=-1
adr%=V:pattern
HLINE x1,y,x2,color,mode,adr%,0
You can't use &X1111111111111111 (16 bits) for the pattern, because bit 15
of a word-variable is a flag for a negative number. Yes, that's why the
largest positive word is 2^15 - 1 (32767). The solution to this little
problem is to assign -1 to the word-variable. You have my word, now all 16
bits are 1. Use BIN$ if you don't believe me.
For very complicated patterns you could use a word-array :
DIM pattern(i)
adr%=V:pattern(0)
(...) ! put fill-pattern in pattern(0) to pattern(i)
HLINE x1,y,x2,color,mode,adr%,i
~~~OOOO~~~
Blitter
The Blitter-TOS (1987) allows you to switch the Blitter on/off. I couldn't
test the following Procedure, because I don't have a Blitter. But if I
understand the function XBIOS 64 (Blitmode) correctly, you could switch
the Blitter on and off from GFA-Basic :
PROCEDURE blitter(switch!)
LOCAL status
status=XBIOS(64,-1)
IF BTST(status,1) ! Blitter available?
IF switch!
status=BSET(status,0) ! Blitter on
ELSE
status=BCLR(status,0) ! Blitter off
ENDIF
~XBIOS(64,status) ! do it
ENDIF
RETURN
By the way, Line A commands do not use the Blitter. The Blitter-chip
contains a hardware-routine that replaces the Line A BitBlt-function
(BITBLT in GFA-Basic). All Mega ST's have a Blitter installed.
~~~OOOO~~~
Read this paragraph carefully, before using the GFAXPERT-files. The files
are not Public Domain!
You are free to use and change all GFAXPERT-files, but only for personal
use. Certainly not for commercial use.
You are invited to copy the original GFAXPERT-disk or the GFAXPRTx.ARC-
files and give these to your friends. But you are not allowed to change
anything on the disk or in the files. If you feel the urge to change
something, don't do it, but write to me (read the chapter 'EPILOGUE').
You are not allowed to sell (files from) the GFAXPERT-disk or one of the
GFAXPRTx.ARC-files. The disk GFAXPERT may only be sold by so-called Public
Domain Clubs if they have my written permission to do so. BBS's are free
to make the original GFAXPRTx.ARC-files available for downloading.
Any part from the text GFAXPERT.DOC or the Procedure-library GFAXPERT.LIB
may be quoted in newsletters or magazines, if accompanied by a reference
like :
from GFAXPERT (2nd ed.) by Han Kempen
I cannot be held responsible for any damage that may result from running a
GFAXPERT-program, using a Procedure from the library GFAXPERT.LIB, or
using information from this text.
(c) Han Kempen, 3 July 1990
EPILOGUE
Well, that's all folks. I'm quite certain there are still a few bugs to be
found in this text and in the Procedure-Library GFAXPERT.LIB. By now you
should have become an expert in GFA-Basic 3.0, so you will be able to spot
them bugs immediately. Please let me know if you find one.
Perhaps you still have some unanswered questions about GFA-Basic. Or an
answer to one of my own questions in this text. Or some neat Procedures.
Or a brilliant program. I would appreciate it very much if you would send
your letter and/or disk to :
Han Kempen
Rubensstraat 12
7741 AR Coevorden
the Netherlands
Do share your ideas, Procedures and programs with others, starting with
me. Consider it a small payment for the GFAXPERT-files. Thanks.
~~~OOOO~~~